package com.xbts.common.utils.bean;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xbts.common.utils.DateUtils;

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Bean 工具类
 *
 * @author xbts
 */
public class BeanUtils extends org.springframework.beans.BeanUtils {
    /**
     * Bean方法名中属性名开始的下标
     */
    private static final int BEAN_METHOD_PROP_INDEX = 3;

    /**
     * 匹配getter方法的正则表达式
     */
    private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");

    /**
     * 匹配setter方法的正则表达式
     */
    private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");

    /**
     * Bean属性复制工具方法。
     *
     * @param dest 目标对象
     * @param src  源对象
     */
    public static void copyBeanProp(Object dest, Object src) {
        try {
            copyProperties(src, dest);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取对象的setter方法。
     *
     * @param obj 对象
     * @return 对象的setter方法列表
     */
    public static List<Method> getSetterMethods(Object obj) {
        // setter方法列表
        List<Method> setterMethods = new ArrayList<Method>();

        // 获取所有方法
        Method[] methods = obj.getClass().getMethods();

        // 查找setter方法

        for (Method method : methods) {
            Matcher m = SET_PATTERN.matcher(method.getName());
            if (m.matches() && (method.getParameterTypes().length == 1)) {
                setterMethods.add(method);
            }
        }
        // 返回setter方法列表
        return setterMethods;
    }

    /**
     * 获取对象的getter方法。
     *
     * @param obj 对象
     * @return 对象的getter方法列表
     */

    public static List<Method> getGetterMethods(Object obj) {
        // getter方法列表
        List<Method> getterMethods = new ArrayList<Method>();
        // 获取所有方法
        Method[] methods = obj.getClass().getMethods();
        // 查找getter方法
        for (Method method : methods) {
            Matcher m = GET_PATTERN.matcher(method.getName());
            if (m.matches() && (method.getParameterTypes().length == 0)) {
                getterMethods.add(method);
            }
        }
        // 返回getter方法列表
        return getterMethods;
    }

    /**
     * 检查Bean方法名中的属性名是否相等。<br>
     * 如getName()和setName()属性名一样，getName()和setAge()属性名不一样。
     *
     * @param m1 方法名1
     * @param m2 方法名2
     * @return 属性名一样返回true，否则返回false
     */

    public static boolean isMethodPropEquals(String m1, String m2) {
        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
    }

    /**
     * 将对象转换为key value
     * A=a&B=b&C=c 格式
     *
     * @param object 对象
     * @return 格式化结果
     */
    public static String formatKeyValuePair(Object object) {
        //准备接受的字符串
        StringBuilder stringBuffer = new StringBuilder();
        //获取对象字段
        String[] fieldNames = BeanUtils.getFiledName(object);
        //遍历所有属性
        for (int j = 0; j < fieldNames.length; j++) {
            //不是第一个并且不是最后一个，拼接&
            if (j != 0) {
                stringBuffer.append("&");
            }
            //获取属性的名字
            String key = fieldNames[j];
            //获取值
            Object value = BeanUtils.getFieldValueByName(key, object);
            assert value != null;
            stringBuffer.append(key).append("=").append(value.toString());
        }
        return stringBuffer.toString();
    }

    /**
     * key value键值对 转换为 对象
     * A=a&B=b&C=c 格式 转换为对象
     *
     * @param str 对象字符串
     * @param t   范型
     * @param <T> 范型
     * @return 格式化结果
     */
    public static <T> T formatKeyValuePair(String str, T t) {
        //填写对参数键值对
        String[] params = str.split("&");

        //获取对象字段
        String[] fieldNames = BeanUtils.getFiledName(t);

        try {
            //循环每个参数
            for (String param : params) {
                String[] keyValues = param.split("=");
                for (int i = 0; i < fieldNames.length; i++) {
                    if (fieldNames[i].equals(keyValues[0])) {
                        Field f = t.getClass().getDeclaredField(fieldNames[i]);
                        f.setAccessible(true);
                        //长度为2 才转换，否则不转
                        if (keyValues.length == 2) {
                            f.set(t, keyValues[1]);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * key value键值对 转换为 对象
     * A=a&B=b&C=c 格式 转换为对象
     *
     * @param object 对象字符串
     * @param t      范型
     * @param <T>    范型
     * @return 格式化结果
     */
    public static <T> T formatKeyValueCloud(Object object, Class<T> t) {
        List<T> list = new ArrayList<>();
        //获取对象字段
        String type = object.getClass().getName();
        if (type.equals("java.util.LinkedHashMap")) {
            JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(object));
            return jsonObjectParseClass(json, t);
        }
//        else if (type.equals("java.util.ArrayList")) {
//            JSONArray objects = JSONArray.parseArray(JSONObject.toJSONString(object));
//            for (int i = 0; i < objects.size(); i++) {
//                JSONObject json = JSONObject.parseObject(objects.get(i).toString());
//                T tt = jsonObjectParseClass(json, t);
//                list.add(tt);
//            }
//            return list;
//        }
        return null;
    }

    /**
     * 根据属性名获取属性值
     *
     * @param json json对象
     * @param t    对象
     * @return 属性值
     */
    public static <T> T jsonObjectParseClass(JSONObject json, Class<T> t) {
        //获取对象字段
        String[] fieldNames = BeanUtils.getFiledName(t);
        T tt = null;
        try {
            tt = t.newInstance();
            int size = json.size();
            for (int i = 0; i < size; i++) {
                String key = json.keySet().toArray()[i].toString();
                for (int j = 0; j < fieldNames.length; j++) {
                    // 下划线转驼峰
                    String humpKey = underlineToHump(key);
                    if (fieldNames[j].equals(humpKey)) {
                        Field f = t.getDeclaredField(fieldNames[j]);
                        f.setAccessible(true);
                        String type = f.getType().getName();

                        Object value = null;
                        if (type.equals("java.lang.String"))
                            value = json.getString(key);
                        else if (type.equals("java.lang.Integer"))
                            value = json.getInteger(key);
                        else if (type.equals("java.lang.Long"))
                            value = json.getLong(key);
                        else if (type.equals("java.lang.Double"))
                            value = json.getDouble(key);
                        else if (type.equals("java.lang.Float"))
                            value = json.getFloat(key);
                        f.set(tt, value);
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tt;
    }

    private static String underlineToHump(String key) {
        StringBuilder result = new StringBuilder();
        String[] a = key.split("_");
        for (String s : a) {
            if (!key.contains("_")) {
                result.append(s);
                continue;
            }
            if (result.length() == 0) {
                result.append(s.toLowerCase());
            } else {
                result.append(s.substring(0, 1).toUpperCase());
                result.append(s.substring(1).toLowerCase());
            }
        }
        return result.toString();
    }


    /**
     * 获取属性名数组
     *
     * @param o 获取字段的对象
     * @return 返回各个字段
     */
    public static String[] getFiledName(Object o) {
        Field[] fields = o.getClass().getDeclaredFields();
        Field[] superFields = o.getClass().getSuperclass().getDeclaredFields();
        String[] fieldNames = new String[fields.length + superFields.length];
        int index = 0;
        for (int i = 0; i < fields.length; i++) {
            fieldNames[index] = fields[i].getName();
            index++;
        }
        for (int i = 0; i < superFields.length; i++) {
            if ("id".equals(superFields[i].getName())) {
                continue;
            }
            fieldNames[index] = superFields[i].getName();
            index++;
        }
        return fieldNames;
    }

    /**
     * 获取属性名数组
     *
     * @param aClass 获取字段的对象
     * @return 返回各个字段
     */
    public static String[] getFiledName(Class<?> aClass) {
        Field[] fields = aClass.getDeclaredFields();
        Field[] superFields = aClass.getSuperclass().getDeclaredFields();
        String[] fieldNames = new String[fields.length + superFields.length];
        int index = 0;
        for (int i = 0; i < fields.length; i++) {
            fieldNames[index] = fields[i].getName();
            index++;
        }
        for (int i = 0; i < superFields.length; i++) {
            if ("id".equals(superFields[i].getName())) {
                continue;
            }
            fieldNames[index] = superFields[i].getName();
            index++;
        }
        return fieldNames;
    }

    /**
     * 根据属性名获取属性值
     *
     * @param fieldName 属性名
     * @param o         对象
     * @return 属性值
     */
    public static Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[]{});
            Object value = method.invoke(o, new Object[]{});
            return value;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取类中的所有属性
     *
     * @param clazz 类
     * @param <T>   泛型
     * @return
     */
    public static <T> Map<String, String> getClassAttributeValue(T clazz) {
        try {
            Object o = clazz.getClass().newInstance();
            Class<?> aClass = o.getClass();
            // 获取类中的所有属性
            Field[] declaredFields = aClass.getDeclaredFields();
            // 判断是否有父类
            if (aClass.getSuperclass() != null) {
                Field[] superFields = aClass.getSuperclass().getDeclaredFields();
                Field[] fields = new Field[declaredFields.length + superFields.length];
                System.arraycopy(declaredFields, 0, fields, 0, declaredFields.length);
                System.arraycopy(superFields, 0, fields, declaredFields.length, superFields.length);
                declaredFields = fields;
            }
            // 获取类中的所有属性
            Map<String, String> hashMap = new HashMap<>();

            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true);
                // 转换时间格式
                Class<?> type = declaredField.getType();
                String name = declaredField.getName();
                if (type == java.util.Date.class && declaredField.get(clazz) != null) {
                    java.util.Date date = (java.util.Date) declaredField.get(clazz);
                    String format = DateUtils.parseDateToStr("yyyy年MM月dd日", date);
                    hashMap.put(name, format);
                    continue;
                }
                if (null == declaredField.get(clazz)){
                    hashMap.put(name, null);
                } else {
                    hashMap.put(name, declaredField.get(clazz) + "");
                }
            }
            return hashMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
